package com.haieros.www.purerunshowsystem.socket;

import android.content.Context;
import android.os.Parcel;
import android.os.Parcelable;
import android.util.Log;
import com.alibaba.fastjson.JSON;
import com.haieros.www.purerunshowsystem.bean.OriginalData;
import com.haieros.www.purerunshowsystem.bean.SocketBean;
import com.haieros.www.purerunshowsystem.bean.UpdateBean;
import com.haieros.www.purerunshowsystem.bean.UpdateInfo;
import org.json.JSONException;

import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.Socket;
import java.nio.ByteBuffer;
import java.nio.ByteOrder;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

import static java.lang.Thread.sleep;

/**
 * Created by W520 on 2017/12/19.
 */

public class SocketUtils implements Parcelable {

    public static final String T = "===Tag";
    //context
    private static Context mContext;
    //Socket
    private static Socket mSocket;
    //接收数据线程
    private static ReadThread mReadThread;
    // 线程池
    private static ExecutorService mThreadPoolSend;
    //int与byte[]转换
    private static IntAndByteArr mIntAndByteArr;
    //SocketBean对象
    private static SocketBean mSocketBean;
    // 输入流对象
    static InputStream mInputStream;
    // 接收服务器发送过来的消息
    static String mReceiveMsg;
    //声明OnDataReceiveListener数据接收接口
    private static OnDataReceiveListener mOnDataReceiveListener;
    //发送服务器消息变量
    private static OutputStream mOutputStream;

    private SocketUtils() {
    }

    /**
     * 静态内部类单例
     */
    private static class SingletonHolder {
        private static final SocketUtils mInstance = new SocketUtils();
    }

    /**
     * 获取SDKUtils初始化,并初始化客户端&服务端
     *
     * @return SDKUtils对象
     */
    public static SocketUtils getSocketUtilsInstance() {
        SocketUtils mInstance = SingletonHolder.mInstance;
        mInstance.init();
        return mInstance;
    }

    /**
     * 初始化
     */
    private void init() {
        // 初始单任务线程池
        mThreadPoolSend = Executors.newSingleThreadExecutor();
        //mIntAndByteArr初始化
        mIntAndByteArr = IntAndByteArr.getIntAndByteArr();
        //初始化接收线程
        mReadThread = new ReadThread();
    }

    /**
     * 接受线程开启
     */
    public void startReadThread() {
        if (mReadThread == null) {
            mReadThread = new ReadThread();
            mReadThread.start();
        } else {
            if (!mReadThread.isAlive()) {
                mReadThread.start();
            }
        }
    }

    /**
     * 是否有数据的监听
     *
     * @param mDataReceiveListener
     */
    public void setOnDataReceiveListener(OnDataReceiveListener mDataReceiveListener) {
        this.mOnDataReceiveListener = mDataReceiveListener;
    }

    /**
     * socket连接
     */
    public synchronized void Connect() {
        try {
            while (true) {
                try {
                    if (mSocket == null || mSocket.isClosed()) {
                        Log.i(T, "connecting...");
                        mSocket = new Socket(SocketBean.MHOST, SocketBean.MPORT);
                    }
                    break;
                } catch (Exception e) {
                    if (mSocket == null)
                        Log.i(T, "ConnectException...");
                    sleep(3000);
                    continue;
                }
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    /**
     * @return true socket连接成功，false 失败
     */
    public static final boolean isConnected() {
        if (mSocket != null) {
            return mSocket.isConnected();
        } else {
            return false;
        }
    }

    /**
     * @return 返回socket是否关闭。true 未关闭，false 关闭。
     */
    public static final boolean isClose() {
        if (mSocket != null) {
            return !mSocket.isClosed();
        } else {
            return false;
        }
    }

    /**
     * 获取升级信息
     */
    public void sendUpdateInfo(UpdateInfo updateInfo) {
        if (updateInfo != null) {
            String msg = JSON.toJSONString(updateInfo);
            Log.i("=======", "========" + msg);
            int len = msg.length();
            sendMSG(msg, len);
        }
    }

    /**
     * @param msg Json
     * @param len Json串长度
     */
    public void sendMSG(final String msg, final int len) {
        mThreadPoolSend.execute(new Runnable() {
            @Override
            public void run() {
                try {
                    Connect();
                    Log.i("send=======", "=======" + msg);
                    // 从Socket 获得输出流对象OutputStream
                    // 该对象作用：发送数据
                    mOutputStream = mSocket.getOutputStream();
                    //将整形int转化成byte[]
                    byte[] bytes1 = mIntAndByteArr.int2byte(len);
                    // 步骤2：写入需要发送的数据到输出流对象中  特别注意：数据的结尾加上换行符才可让服务器端的readline()停止阻塞
//                        mOutputStream.write((msg.toString()+"\n").getBytes("utf-8"));
                    byte[] bytes2 = (msg.toString()).getBytes("utf-8");
                    mOutputStream.write(mIntAndByteArr.byteMerger(bytes1, bytes2));
//                        mOutputStream.write((msg.toString()).getBytes("utf-8"));
                    // 发送数据到服务端
                    mOutputStream.flush();

                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        });
    }

    //打印byte[]
    private static String byte2hex(byte[] buffer) {
        String h = "";

        for (int i = 0; i < buffer.length; i++) {
            String temp = Integer.toHexString(buffer[i] & 0xFF);
            if (temp.length() == 1) {
                temp = "0" + temp;
            }
            h = h + " " + temp;
        }

        return h;

    }

    private static ByteBuffer mRemainingBuf;

    /**
     * 接收 服务器消息
     */
    private class ReadThread extends Thread {
        @Override
        public void run() {
            super.run();
            while (!isInterrupted()) {
                try {
                    Connect();
                    OriginalData originalData = new OriginalData();
                    ByteBuffer headBuf = ByteBuffer.allocate(4);
                    headBuf.order(ByteOrder.BIG_ENDIAN);

                        //读取字节流
                        mInputStream = mSocket.getInputStream();
                        int readbyte = 0;//inputStream读到的每一个字节，用于判断是否-1
                        if (mRemainingBuf != null) {
                            mRemainingBuf.flip();
                            int length = Math.min(mRemainingBuf.remaining(), 4);
                            headBuf.put(mRemainingBuf.array(), 0, length);
                            if (length < 4) {
                                //there are no data left
                                mRemainingBuf = null;
                                for (int i = 0; i < 4 - length; i++) {
                                    if (headBuffPutData(headBuf)) return;
                                }
                            } else {
                                mRemainingBuf.position(4);
                            }
                        } else {
                            for (int i = 0; i < headBuf.capacity(); i++) {
                                if (headBuffPutData(headBuf)) continue;
                            }
                        }
                        originalData.setHeadBytes(headBuf.array());

                        int bodyLength = getBodyLength(originalData.getHeadBytes(), ByteOrder.BIG_ENDIAN);
                        if (bodyLength > 0) {
                            if (bodyLength > 10 * 1024 * 1024) {//大于最大的读取容量,说明数据有问题
                                Log.i("数据异常", "we can't read data bigger than===== " + 10 + "Mb"+"===length is"+bodyLength);
                                //数据异常，Socket重连
                                reConnect();
                                continue;
                            }
                            ByteBuffer byteBuffer = ByteBuffer.allocate(bodyLength);
                            byteBuffer.order(ByteOrder.BIG_ENDIAN);
                            if (mRemainingBuf != null) {
                                int bodyStartPosition = mRemainingBuf.position();
                                int length = Math.min(mRemainingBuf.remaining(), bodyLength);
                                byteBuffer.put(mRemainingBuf.array(), bodyStartPosition, length);
                                mRemainingBuf.position(bodyStartPosition + length);
                                if (length == bodyLength) {
                                    if (mRemainingBuf.remaining() > 0) {//there are data left
                                        mRemainingBuf = ByteBuffer.allocate(mRemainingBuf.remaining());
                                        mRemainingBuf.order(ByteOrder.BIG_ENDIAN);
                                        mRemainingBuf
                                                .put(mRemainingBuf.array(), mRemainingBuf.position(),
                                                        mRemainingBuf.remaining());
                                    } else {//there are no data left
                                        mRemainingBuf = null;
                                    }
                                    //cause this time data from remaining buffer not from channel.
                                    originalData.setBodyBytes(byteBuffer.array());
                                    //解析读取到的json数据
                                    readData(originalData);
                                    return;
                                } else {//there are no data left in buffer and some data pieces in channel
                                    mRemainingBuf = null;
                                }
                            }
                            readBodyFromChannel(byteBuffer);
                            originalData.setBodyBytes(byteBuffer.array());
                        } else if (bodyLength == 0) {
                            originalData.setBodyBytes(new byte[0]);
                        } else if (bodyLength < 0) {
                            //Socket重连
                            reConnect();
                            continue;
                        }
                        //解析读取到的json数据
                        readData(originalData);

                } catch (IOException e) {
                    e.printStackTrace();
                } catch (Exception e) {
                    e.printStackTrace();
                }
            }
        }

        /**
         * 缓存Socket读取的字节，如果inputStream.read()返回-1，socket重连
         *
         * @param headBuf
         * @return
         * @throws IOException
         * @throws InterruptedException
         */
        private boolean headBuffPutData(ByteBuffer headBuf) throws IOException, InterruptedException {
            int readbyte = mInputStream.read();
            if(readbyte==-1&&!mSocket.isClosed()){
                Log.d(T, "读到了-1...............");
                reConnect();
                return true;
            }else if (readbyte != -1) {
                headBuf.put((byte) readbyte);
                return false;
            }
            return false;
        }

        //socket重连
        private void reConnect() throws InterruptedException ,IOException {
            Log.d(T,"-1 对流关闭----------------read");
            if (!mSocket.isClosed()) {
                mRemainingBuf = null;
                mSocket.close();
            }
            Log.d(T,"---------sockethashcode："+mSocket.hashCode()+"--------------close");
        }
    }

    /**
     * 解析读取到的json数据
     *
     * @param originalData
     */
    private static void readData(OriginalData originalData) {
        mReceiveMsg = new String(originalData.getBodyBytes());
        //判断数据类型
        Log.i("收到数据===", "========开始解析========" + mReceiveMsg);
        if (mReceiveMsg.length() > 0) {
            try {
                org.json.JSONObject jsonObject = new org.json.JSONObject
                        (mReceiveMsg);
                if (jsonObject.has("daemon_version") && jsonObject.has
                        ("daemon_path")
                        && jsonObject.has("control_app_version") && jsonObject
                        .has("control_app_path")
                        && jsonObject.has("display_app_version") && jsonObject
                        .has("display_app_path")) {
                    //升级
                    mOnDataReceiveListener.onUpdateURL(JSON.parseObject(mReceiveMsg,
                            UpdateBean.class));
                }
            } catch (JSONException e) {
                e.printStackTrace();
            }
        }
    }

    //获取json长度
    public static int getBodyLength(byte[] header, ByteOrder byteOrder) {
        if (header == null || header.length == 0) {
            return 0;
        }
        return BytesUtils.byte2Int(header);
    }

    private static void readBodyFromChannel(ByteBuffer byteBuffer) throws IOException {
        while (byteBuffer.hasRemaining()) {
            try {
                byte[] bufArray = new byte[1024];
                int len = mInputStream.read(bufArray);
                if (len < 0) {
                    break;
                }
                int remaining = byteBuffer.remaining();
                if (len > remaining) {
                    byteBuffer.put(bufArray, 0, remaining);
                    mRemainingBuf = ByteBuffer.allocate(len - remaining);
                    mRemainingBuf.order(ByteOrder.BIG_ENDIAN);
                    mRemainingBuf.put(bufArray, remaining, len - remaining);
                } else {
                    byteBuffer.put(bufArray, 0, len);
                }
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
        Log.i("SocketUtils", "read total bytes: " + BytesUtils.toHexStringForLog(byteBuffer.array()));
        Log.i("SocketUtils", "read total length:" + (byteBuffer.capacity() - byteBuffer.remaining()));
    }

    /**
     * 断开客户端 & 服务器的连接
     */
    public static void closeCS() {

        try {
            if (isConnected()) {
                // 断开 客户端发送到服务器 的连接，即关闭输出流对象OutputStream
                if (mOutputStream != null) {
                    mOutputStream.close();
                }
                // 断开 服务器发送到客户端 的连接，即关闭输入流读取器对象BufferedReader
                if (mInputStream != null) {
                    mInputStream.close();
                }
                if (mReadThread != null) {
                    mReadThread.interrupt();
                }
                //清空缓存的byteBuffer
                mRemainingBuf = null;
                // 最终关闭整个Socket连接
                mSocket.close();
            }
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    protected SocketUtils(Parcel in) {
    }

    public static final Creator<SocketUtils> CREATOR = new Creator<SocketUtils>() {
        @Override
        public SocketUtils createFromParcel(Parcel in) {
            return new SocketUtils(in);
        }

        @Override
        public SocketUtils[] newArray(int size) {
            return new SocketUtils[size];
        }
    };

    @Override
    public int describeContents() {
        return 0;
    }

    @Override
    public void writeToParcel(Parcel dest, int flags) {
    }
}
